#pragma once

#include <vector>
#include <gtl/string/str.h>

namespace gtl
{
	
class keyboard
{
public:
	static bool press(const tchar* key)
	{
		if(gtl::tstr_warp(key).empty())
			return false;

		std::vector<gtl::tstr> keys;
		gtl::tstr_warp(key).split(keys, _T("+"));
		if(keys.empty())
			return false;

		WORD ky = get_key(keys.back());
		if(ky == 0)
			return false;

		std::vector<WORD> vkeys;
		get_vkeys(key, vkeys);

		for(size_t i = 0; i < vkeys.size(); ++i)
		{
			 keybd_event(vkeys[i], 0, 0 ,0);
		}

		keybd_event(ky, 0, 0, 0);
		keybd_event(ky, 0, KEYEVENTF_KEYUP, 0);

		for(size_t i = 0; i < vkeys.size(); ++i)
		{
			keybd_event(vkeys[i], 0, KEYEVENTF_KEYUP ,0);
		}

		return true;
	}

public:
	static void get_vkey(const gtl::tstr& key, bool& ctrl, bool& shift, bool& alt, bool& win)
	{
		std::vector<gtl::tstr> keys;
		key.split(keys, _T("+"));
		for(size_t i = 0; i < keys.size(); ++i)
		{
			if(keys[i].icmp(_T("ctrl")))
				ctrl = true;
			else if(keys[i].icmp(_T("shift")))
				shift = true;
			else if(keys[i].icmp(_T("alt")))
				alt = true;
			else if(keys[i].icmp(_T("win")))
				win = true;
		}
	}

	static void get_vkeys(const gtl::tstr& key, std::vector<WORD>& vkeys)
	{
		std::vector<gtl::tstr> keys;
		key.split(keys, _T("+"));
		for(size_t i = 0; i < keys.size(); ++i)
		{
			if(keys[i].icmp(_T("ctrl")))
				vkeys.push_back(VK_CONTROL);
			else if(keys[i].icmp(_T("shift")))
				vkeys.push_back(VK_SHIFT);
			else if(keys[i].icmp(_T("alt")))
				vkeys.push_back(VK_MENU);
			else if(keys[i].icmp(_T("win")))
				vkeys.push_back(VK_LWIN);
		}
	}

	static WORD get_key(const gtl::tstr& key)
	{
		static struct
		{
			const gtl::tchar* desc;
			WORD key;
		} keys[] = {
			_T("Left mouse button"),		VK_LBUTTON,
			_T("Right mouse button"),		VK_RBUTTON,
			_T("Control-break processing"),	VK_CANCEL,
			_T("Middle mouse button"),		VK_MBUTTON,
			_T("Backspace"),				VK_BACK,
			_T("Tab"),						VK_TAB,
			_T("Clear"),					VK_CLEAR,
			_T("Enter"),					VK_RETURN,
			_T("Shift"),					VK_SHIFT,
			_T("Ctrl"),						VK_CONTROL,
			_T("Alt"),						VK_MENU,
			_T("Pause"),					VK_PAUSE,
			_T("CapsLock"),					VK_CAPITAL,
			_T("Esc"),						VK_ESCAPE,
			_T("Space"),					VK_SPACE,
			_T("Page Up"),					VK_PRIOR, 
			_T("Page Down"),				VK_NEXT,
			_T("End"),						VK_END,
			_T("Home"),						VK_HOME,
			_T("Left"),						VK_LEFT,
			_T("Up"),						VK_UP,
			_T("Right"),					VK_RIGHT,
			_T("Down"),						VK_DOWN,
			_T("Select"),					VK_SELECT,
			_T("Excute"),					VK_EXECUTE,
			_T("Print Screen"),				VK_SNAPSHOT,
			_T("NumLock"),					VK_NUMLOCK,
			_T("Insert"),					VK_INSERT,
			_T("Delete"),					VK_DELETE,
			_T("Help"),						VK_HELP,
			_T("0"),						'0',
			_T("1"),						'1',
			_T("2"),						'2',
			_T("3"),						'3',
			_T("4"),						'4',
			_T("5"),						'5',
			_T("6"),						'6',
			_T("7"),						'7',
			_T("8"),						'8',
			_T("9"),						'9',
			_T("A"),						'A',
			_T("B"),						'B',
			_T("C"),						'C',
			_T("D"),						'D',
			_T("E"),						'E',
			_T("F"),						'F',
			_T("G"),						'G',
			_T("H"),						'H',
			_T("I"),						'I',
			_T("J"),						'J',
			_T("K"),						'K',
			_T("L"),						'L',
			_T("M"),						'M',
			_T("N"),						'N',
			_T("O"),						'O',
			_T("P"),						'P',
			_T("Q"),						'Q',
			_T("R"),						'R',
			_T("S"),						'S',
			_T("T"),						'T',
			_T("U"),						'U',
			_T("V"),						'V',
			_T("W"),						'W',
			_T("X"),						'X',
			_T("Y"),						'Y',
			_T("Z"),						'Z',
			_T("Left windows"),				VK_LWIN,
			_T("Right windows"),			VK_RWIN,
			_T("Applications"),				VK_APPS,
			_T("Num pad 0"),				VK_NUMPAD0,
			_T("Num pad 1"), 				VK_NUMPAD1,
			_T("Num pad 2"), 				VK_NUMPAD2,
			_T("Num pad 3"), 				VK_NUMPAD3,
			_T("Num pad 4"), 				VK_NUMPAD4,
			_T("Num pad 5"), 				VK_NUMPAD5,
			_T("Num pad 6"), 				VK_NUMPAD6,
			_T("Num pad 7"), 				VK_NUMPAD7,
			_T("Num pad 8"), 				VK_NUMPAD8,
			_T("Num pad 9"),				VK_NUMPAD9,
			_T("Multiply"),					VK_MULTIPLY,
			_T("Add"),						VK_ADD,
			_T("Separator"),				VK_SEPARATOR,
			_T("Subtract"),					VK_SUBTRACT,
			_T("Decimal Point"),			VK_DECIMAL,
			_T("Divide"),					VK_DIVIDE,
			_T("F1"),						VK_F1,
			_T("F2"),						VK_F2,
			_T("F3"),						VK_F3,
			_T("F4"),						VK_F4,
			_T("F5"),						VK_F5,
			_T("F6"),						VK_F6,
			_T("F7"),						VK_F7,
			_T("F8"),						VK_F8,
			_T("F9"),						VK_F9,
			_T("F10"),						VK_F10,
			_T("F11"),						VK_F11,
			_T("F12"),						VK_F12,
			_T("F13"),						VK_F13,
			_T("F14"),						VK_F14,
			_T("F15"),						VK_F15,
			_T("F16"),						VK_F16,
			_T("F17"),						VK_F17,
			_T("F18"),						VK_F18,
			_T("F19"),						VK_F19,
			_T("F20"),						VK_F20,
			_T("F21"),						VK_F21,
			_T("F22"),						VK_F22,
			_T("F23"),						VK_F23,
			_T("F24"),						VK_F24,
			_T("Attn"),						VK_ATTN,
			_T("CrSel"),					VK_CRSEL,
			_T("ExSel"),					VK_EXSEL,
			_T("Erase"),					VK_EREOF,
			_T("Play"),						VK_PLAY,
			_T("Zoom"),						VK_ZOOM,
			_T("Reserved for future use"),	VK_NONAME,
			_T("PA1"),						VK_PA1,
			_T("Clear(OEM)"),				VK_OEM_CLEAR,

			_T("\\"),						'\\',
			_T("-"),						'-',
			_T("="),						'=',
			_T("["),						'[',
			_T("]"),						']',
			_T(";"),						';',
			_T("\'"),						'\'',
			_T(","),						',',
			_T("."),						'.',
			_T("/"),						'/',
			_T("`"),						'`'
		};

		for(int i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i)
		{
			if(key.icmp(keys[i].desc))
				return keys[i].key;
		}

		return 0;
	}
};

} // end of namespace gtl